/**
 * Stok3d - getting you stoked on Flash Player native 3D
 * Copyright (C) 2009  David Lenaerts
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Author information:
 * David Lenaerts
 * url: http://www.derschmale.com
 * mail: david.lenaerts@gmail.com
 * 
 */

package
{
	import com.derschmale.stok3d.filters.ParallaxFilter;
	import com.derschmale.stok3d.filters.PhongFilter;
	import com.derschmale.stok3d.utils.NormalMapUtil;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	
	/**
	 * Native FP10 3D Parallax Mapping demo, in combination with Phong Shading
	 * This also shows the use of NormalMapUtil.generateFromHeightMap to create
	 * normal maps from height/bump maps
	 */
	
	[SWF(width="1024", height="768", frameRate="30", backgroundColor="0x000000")]
	public class ParallaxExample extends Sprite
	{
		[Embed(source="/../exampleAssets/parallax/bg.jpg")]
		private var Background : Class;
		
		[Embed(source="/../exampleAssets/parallax/masonry-wall-texture.jpg")]
		private var Texture : Class;
		
		[Embed(source="/../exampleAssets/parallax/masonry-wall-bump-map.jpg")]
		private var HeightMap : Class;
		
		private var _startX : Number;
		private var _startY : Number;
		
		private var _mouseDown : Boolean;
		
		private var _surface : Sprite;
		
		private var _parallax : ParallaxFilter;
		private var _phong : PhongFilter;
		private var _lightRotation : Number = 0;
		
		private var _glossCount : int = 5;
		
		public function ParallaxExample()
		{
			initView();
			initFilter();
			
			stage.addEventListener(MouseEvent.MOUSE_DOWN, handleMouseDown);
			stage.addEventListener(MouseEvent.MOUSE_UP, handleMouseUp);
			stage.addEventListener(KeyboardEvent.KEY_UP, handleKeyUp);
			addEventListener(Event.ENTER_FRAME, handleEnterFrame);
		}
		
		private function initView() : void
		{
			addChild(new Background());
			// init background
			var textField : TextField = new TextField();
			
			textField.textColor = 0xffffff;
			textField.multiline = true;
			textField.text = 	"Move mouse : Move surface\n" + 
								"Click & drag : Rotate surface\n" + 
								"s/d : Change surface relief\n" + 
								"f/g : Change number of iterations";
			textField.width = textField.textWidth + 10;
			textField.height = textField.textHeight + 10;
			textField.x = stage.stageWidth-textField.width;
			addChild(textField);
			// init rotatable surface, make sure registration point is in center
			var bmp : Bitmap = new Texture();
			bmp.smoothing = false;
			bmp.x = -bmp.width*.5;
			bmp.y = -bmp.height*.5;
			_surface = new Sprite();
			_surface.addChild(bmp);
			
			_surface.z = 600;
			
			// position and scale
			_surface.x = stage.stageWidth*.5;
			_surface.y = stage.stageHeight*.5;
			
			_surface.scaleY = 2;
			_surface.scaleX = 2;
			
			addChild(_surface);
		}
		
		/**
		 * Create the filters and assign them to the surface
		 */
		private function initFilter() : void
		{
			var heightMap : BitmapData = new HeightMap().bitmapData;
			// create a normal map from the height map
			var normalMap : BitmapData = NormalMapUtil.generateFromHeightMap(heightMap);
			
			_parallax = new ParallaxFilter(heightMap, normalMap, 5, -20, 40);
			_parallax.update(_surface);
			
			// add a phong filter, will be a bit slow but it makes the parallax effect more visible
			_phong = new PhongFilter(0.5, 200, normalMap, 0.5);//new NormalMap().bitmapData, 0.5);
			_phong.ambientColor = 0x000008;
			_phong.update(_surface);
			
			// assign the filters. Note that we add the parallax filter last because it also needs to offset the phong shading
			_surface.filters = [ _phong, _parallax ];
		}
		
		private function handleKeyUp(event : KeyboardEvent) : void
		{
			switch (event.charCode) {
				case 100:
					_parallax.scale+=4;
					if (_parallax.scale > 80) _parallax.scale = 80;
					_parallax.bias = -_parallax.scale*.5;
					break;
				case 115:
					_parallax.scale-=4;
					if (_parallax.scale < 0) _parallax.scale = 0;
					_parallax.bias = -_parallax.scale*.5;
					break;
				case 102:
					_parallax.numSteps--;
					if (_parallax.numSteps < 1) _parallax.numSteps = 1;
					break;
				case 103:
					_parallax.numSteps++;
					if (_parallax.numSteps > 8) _parallax.numSteps = 8;
					break;
			}
		}
		
		/**
		 * Indicate rotation has started with the current mouse position as motion reference
		 */
		private function handleMouseDown(event : MouseEvent) : void
		{
			_mouseDown = true;
			_startX = mouseX;
			_startY = mouseY;
		}
		
		/**
		 * Indicate rotation has stopped
		 */
		private function handleMouseUp(event : MouseEvent) : void
		{
			_mouseDown = false;
		}
		
		/**
		 * Update filter and surface position
		 */
		private function handleEnterFrame(event : Event) : void
		{
			_lightRotation += .03;
			_phong.lightPosition.x = Math.sin(_lightRotation)*1000;
			_phong.lightPosition.y = Math.sin(_lightRotation*2)*100;
			_phong.lightPosition.z = -2000;
			
			// rotate if mouse is down
			if (_mouseDown) {
				_surface.rotationY += (_startX-mouseX)*.01;
		 		_surface.rotationX += (_startY-mouseY)*.01;
		 	}
		 	else {
		 		_surface.x = mouseX;
				_surface.y = mouseY;
		 	}
		 	_parallax.update(_surface);
		 	_phong.update(_surface);
			_surface.filters = [ _phong, _parallax ];
		}
	}
}